package edu.gatech.cs2340.mule.model;
import java.awt.Color;
import java.awt.Point;
import java.io.Serializable;
import java.util.LinkedList;

/**
 * 
 * This class represents a player in a game of MULE.
 * 
 * @author Tyler Litrel
 *
 */
public class Player implements Serializable {
	private static final long serialVersionUID = 1852373153139600096L;

	private static final int PROPERTY_SCORE_MULTIPLIER = 300;
	
	private int moneyAmount;
	private int foodAmount;
	private int smithOreAmount;
	private int energyAmount;	
	private Color playerColor;
	private String playerName;
	private Race playerRace;
	private LinkedList<Point> ownedLand;
	private boolean inLast;
	
	/**
	 * 
	 * @param color The player's color
	 * @param name The player's name
	 * @param race The player's race
	 */
	public Player(Color color, String name, Race race){
		playerColor = color;
		playerName = name;
		playerRace = race;
		moneyAmount = playerRace.returnMoney();
		foodAmount = 0;
		smithOreAmount = 0;
		energyAmount = 0;
		ownedLand = new LinkedList<Point>();
		inLast = false;
	}
	
	public int[] calculateProduction(Map gameMap) {
		int[] productionChange = new int[3];
		for(Point p : ownedLand) {
			TerrainTile currentTile = (TerrainTile) gameMap.getMapTileAt(p);
			if(energyAmount > 0) { // Must have energy for production
				int oldFood = foodAmount;
				int oldEnergy = energyAmount;
				int oldSmithore = smithOreAmount;
				foodAmount += currentTile.calcFoodProduction();
				energyAmount += currentTile.calcEnergyProduction();
				smithOreAmount += currentTile.calcSmithoreProduction();
				if(oldFood != foodAmount || oldEnergy != energyAmount || oldSmithore != smithOreAmount) {
					energyAmount--;
				}
				productionChange[0] += foodAmount - oldFood;
				productionChange[1] += energyAmount - oldEnergy;
				productionChange[2] += smithOreAmount - oldSmithore;
			}
		}
		
		for(int i = 0; i < productionChange.length; i++) {
			productionChange[i] = Math.max(productionChange[i], 0);
		}
		
		return productionChange;	
	}
	
	/**
	 * 
	 * Determines if the player can afford the transaction based on the amount of money
	 * the transaction will need and the amount of money the player has
	 * 
	 * @param transactionPrice The amount the transaction will cost
	 * @return True if the player can afford the transaction, false otherwise
	 */
	public boolean canAffordTransaction(int transactionPrice) {
		return (transactionPrice <= moneyAmount);
	}
	
	/**
	 * 
	 * Determines if the location on the map is owned by this player
	 * 
	 * @param location The location to check if it is owned
	 * @return True if the player owns this location, false otherwise
	 */
	public boolean isOwned(Point location) {
		return ownedLand.contains(location);
	}
	
	/**
	 * 
	 * Adds the new property to the player's owned land inventory
	 * 
	 * @param location The location of the land now owned
	 */
	public void addOwnedLand(Point location) {
		ownedLand.add(location);
	}
	
	/**
	 * 
	 * Removes the property from the player's owned land inventory
	 * 
	 * @param location The location of the land to be removed
	 */
	public void removeOwnedLand(Point location) {
		ownedLand.remove(location);
	}
	
	/**
	 * 
	 * @return The amount of money the player has
	 */
	public int getMoneyAmount() {
		return moneyAmount;
	}
	
	/**
	 * 
	 * @param amount The change in the amount of money the player has
	 */
	public void setMoneyAmount(int amount) {
		moneyAmount += amount;
		moneyAmount = Math.max(moneyAmount, 0);
	}
	
	/**
	 * 
	 * @return The amount of food the player has
	 */
	public int getFoodAmount() {
		return foodAmount;
	}
	
	/**
	 * 
	 * @param amount The change in the amount of food the player has
	 */
	public void setFoodAmount(int amount) {
		foodAmount += amount; 
		foodAmount = Math.max(foodAmount, 0);
	}
	
	/**
	 * 
	 * @return The amount of smithore the player has
	 */
	public int getSmithOreAmount() {
		return smithOreAmount;
	}
	
	/**
	 * 
	 * @param amount The change in the amount of smithore the player has
	 */
	public void setSmithOreAmount(int amount) {
		smithOreAmount += amount;
		smithOreAmount = Math.max(smithOreAmount, 0);
	}
	
	/**
	 * 
	 * @return The amount of energy the player has
	 */
	public int getEnergyAmount(){
		return energyAmount;
	}
	
	/**
	 * 
	 * @param amount The change in the amount of energy the player has
	 */
	public void setEnergyAmount(int amount) {
		energyAmount += amount;
		energyAmount = Math.max(energyAmount, 0);
	}
	
	/**
	 * 
	 * @return The player's name
	 */
	public String getPlayerName() {
		return playerName;
	}
	
	/**
	 * 
	 * @return The player's race
	 */
	public Race getPlayerRace() {
		return playerRace;
	}
	
	/**
	 * 
	 * @return The player's color
	 */
	public Color getPlayerColor() {
		return playerColor;
	}
	
	/**
	 * 
	 * @param name The player's name
	 */
	public void setPlayerName(String name) {
		playerName = name;
	}
	
	/**
	 * 
	 * @return Whether or not the player is currently in last place
	 */
	public boolean isInLast() {
		return inLast;
	}
	
	/**
	 * 
	 * @param isInLast Whether or not the player is currently in last place
	 */
	public void setInLast(boolean isInLast) {
		inLast = isInLast;
	}
	
	/**
	 * 
	 * @param color The player's color
	 */
	public void setPlayerColor(Color color) {
		playerColor = color;
	}
	
	/**
	 * 
	 * @param race The player's race
	 */
	public void setPlayerRace(Race race) {
		playerRace = race;
	}
	/**
	 * 
	 * @return r The number of land tiles a player owns
	 */
	public int totalLand() {
		return ownedLand.size();
	}
	
	/**
	 * 
	 * Calculates the player's current score based on the amount of resources, money,
	 * and property owned.
	 * 
	 * @return The player's current score
	 */
	public int calculatePlayerScore() {
		return (moneyAmount + 30 * foodAmount + 25 * energyAmount + 50 * smithOreAmount
				+ ownedLand.size() * PROPERTY_SCORE_MULTIPLIER);
	}
}
